【cocos2dx 3.2】自己写的虚拟摇杆,可换皮肤

http://www.cocoachina.com/bbs/3g/read.php?tid=226121

在项目中写了个虚拟摇杆控件,在这里分享给大家,可以根据自己的需要换贴图皮肤

代码中会用到3个贴图,这3个贴图可以替换,在这里先介绍下3个贴图的作用,他们分别是摇杆控件背景,摇杆移动范围背景,以及摇杆本身

摇杆控件背景定义了虚拟摇杆空间的大小,以及触摸大小,在该范围内的触摸都会触发摇杆的移动
摇杆移动范围背景,这一层定义了摇杆可运动的范围。 移动范围是一个圆,该圆的半径是移动范围背景贴图宽的一半,见黑色大圆圈
摇杆本身贴图,这一层中有个黑色小圆,这个小圆定义了摇杆和移动范围碰触的边缘。

下面是代码,在INIT函数里修改3个贴图文件,就可以实现自己的摇杆了

#define WIDTH(obj) (obj)->getContentSize().width
#define HEIGHT(obj) (obj)->getContentSize().height
class Joystick : public Sprite
{
public:
CREATE_FUNC(Joystick);
virtual bool init();
typedef std::function<void(const Vec2& newPos, const Vec2& lastPos)> JoystickHandler;
void setJoystickPositionChangeHandler(JoystickHandler);
CC_SYNTHESIZE(float, _controlDiameter, ControlDiameter);
private:
Sprite* _stick;
Sprite* _frame;
Vec2 _lastPos;
JoystickHandler _handler;
EventListenerTouchOneByOne* _touchEventListener;
bool onTouchBegan(Touch*, Event*);
void onTouchMoved(Touch*, Event*);
void onTouchEnded(Touch*, Event*);
void onTouchCancelled(Touch*, Event*);
void handleTouchChange(Touch*);
};
bool Joystick::init()
{
if (!Sprite::initWithSpriteFrameName("joystickbackground.png"))
return false;
_lastPos = Vec2::ZERO;
_frame = Sprite::createWithSpriteFrameName("joystickframebackground.png");
_frame->setPosition(WIDTH(this) / 2, HEIGHT(this) / 2);
addChild(_frame);
_stick = Sprite::createWithSpriteFrameName("joystick.png");
_stick->setPosition(WIDTH(_frame) / 2, HEIGHT(_frame) / 2);
_frame->addChild(_stick);
_controlDiameter = WIDTH(_frame) - WIDTH(_stick);
_touchEventListener = EventListenerTouchOneByOne::create();
_touchEventListener->onTouchBegan = CC_CALLBACK_2(Joystick::onTouchBegan, this);
_touchEventListener->onTouchMoved = CC_CALLBACK_2(Joystick::onTouchMoved, this);
_touchEventListener->onTouchEnded = CC_CALLBACK_2(Joystick::onTouchEnded, this);
_touchEventListener->onTouchCancelled = CC_CALLBACK_2(Joystick::onTouchCancelled, this);
_touchEventListener->setSwallowTouches(true);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(_touchEventListener, this);
return true;
}
void Joystick::setJoystickPositionChangeHandler(JoystickHandler handler)
{
_handler = handler;
}
bool Joystick::onTouchBegan(Touch* touch, Event* event)
{
if (this->getBoundingBox().containsPoint(touch->getLocation()))
{
handleTouchChange(touch);
return true;
}
return false;
}
void Joystick::onTouchMoved(Touch* touch, Event* event)
{
if (this->getBoundingBox().containsPoint(touch->getLocation()))
handleTouchChange(touch);
}
void Joystick::onTouchEnded(Touch* touch, Event* event)
{
static Vec2 origin = Vec2(WIDTH(_frame) / 2, HEIGHT(_frame) / 2);
_stick->setPosition(origin);
if (!_handler._Empty())
_handler(Vec2::ZERO, Vec2::ZERO);
_lastPos = Vec2::ZERO;
}
void Joystick::onTouchCancelled(Touch* touch, Event* event)
{
onTouchEnded(touch, event);
}
void Joystick::handleTouchChange(Touch* touch)
{
static Vec2 origin = Vec2(WIDTH(_frame) / 2, HEIGHT(_frame) / 2);
static float bigR = WIDTH(_frame) / 2;
static float smallR = WIDTH(_stick) / 2;
Vec2 hit = this->_frame->convertToNodeSpaceAR(touch->getLocation());
if (hit.getDistance(Vec2::ZERO) + smallR > bigR)
{
float x = (bigR - smallR) / sqrt(1 + hit.y * hit.y / hit.x / hit.x);
float y = abs(hit.y / hit.x * x);
if (hit.x > 0)
{
if (hit.y > 0)
{
hit.x = x;
hit.y = y;
}
else
{
hit.x = x;
hit.y = -y;
}
}
else
{
if (hit.y > 0)
{
hit.x = -x;
hit.y = y;
}
else
{
hit.x = -x;
hit.y = -y;
}
}
}
_stick->setPosition(hit + origin);
if (!_handler._Empty())
_handler(hit, _lastPos);
_lastPos = hit;
}

因为是自己项目内部用的,所以没把3个贴图参数化